// ==UserScript==
// @name				HWM - Map
// @namespace			figey_hwm_
// @description			Replace standard map
// @version				0.1.1
// @run-at				document-end
// @grant				GM_deleteValue
// @grant				GM_getValue
// @grant				GM_info
// @grant				GM_listValues
// @grant				GM_notification
// @grant				GM_setValue
// @noframe
// @require				https://notabug.org/figey/localDataStorage/raw/8018b121fb20340d325f45999a308b02b8d761e1/localDataStorage-1.2.0.trim.js
// @require				https://notabug.org/figey/hwm_scripts/raw/59e98a179ba73cc408884238fa4c7c0285622194/src/core.js
// @include				/^https?:\/\/(www\.)?(heroeswm\.ru|lordswm\.com)\/map\.php.*/
// @include				/^https?:\/\/(www\.)?(heroeswm\.ru|lordswm\.com)\/mercenary_guild\.php.*/
// @include				/^https?:\/\/(www\.)?(heroeswm\.ru|lordswm\.com)\/group_wars\.php.*/
// ==/UserScript==
'use strict';

/**
 * TODO
 * notification icons?
 * Detect if we can move
 * Premium transport support
 */

/**
 * Script settings
 */
const scriptSettings = {
	move: { sectorID: 0 },

	gm: {
		'map_replace': { name: 'Заменять карту', value: false },
		'map_hideonmove': { name: 'Скрывать карту при перемещении', value: false },
		'map_notify': { name: 'Оповещать при событиях', value: false }
	}
};

/**
 * Init
 */
HWMMap.init();
SettingsTab.init();
const options = new GMSettings(scriptSettings);
let moveTimeoutID = null;

/**
 * Map object for DOM
 */
const MapObject = {
	/**
	 * draw map first time
	 * create DOM elements
	 */
	init(){
		// check if already created
		const mapID = GM_info.script.namespace + 'map';
		const testMap = document.getElementById(mapID);
		if( testMap ){
			return;
		}

		const table = document.createElement('table');
		table.id = mapID;
		table.style.display = 'none';
		table.style.paddingTop = '20px';

		// calculate map size
		const mapSize = {
			x: { min: 50, max: 50 },
			y: { min: 50, max: 50 }
		};
		HWMMap.sectorList.forEach(function(s){
			if( s.x > mapSize.x.max ){ mapSize.x.max = s.x; }
			if( s.y > mapSize.y.max ){ mapSize.y.max = s.y; }
			if( s.x < mapSize.x.min ){ mapSize.x.min = s.x; }
			if( s.y < mapSize.y.min ){ mapSize.y.min = s.y; }
		});

		// fill the table
		for( let y = mapSize.y.min; y <= mapSize.y.max; ++y ){
			const tr = document.createElement('tr');
			for( let x = mapSize.x.min; x <= mapSize.x.max; ++x ){
				const td = document.createElement('td');
				const sectorID = HWMMap.getSectorIDFromXY(x,y);
				// skip unexisting sectors
				if( sectorID ){
					td.id = GM_info.script.namespace + "sector_" + sectorID;
					td.dataset.sectorId = sectorID;
					td.align = 'center';
					td.style.outline = '1px solid';
					td.style.outlineOffset = '-1px';
					td.style.fontSize = '0.7em;';
					td.style.textDecorationLine = 'underline';

					td.addEventListener('mouseenter', function(event){
						const sID = event.target.dataset.sectorId;
						event.target.childNodes.forEach( function(node){
							node.style.display = ( node.tagName == 'IMG' ? '' : 'none');
						});
					});
					td.addEventListener('mouseleave', function(event){
						const sID = event.target.dataset.sectorId;
						event.target.childNodes.forEach(function(node){
							node.style.display = node.tagName == 'IMG' ? 'none' : '' ;
						});
					});

					const sectorName = document.createElement('span');
					
					sectorName.innerHTML = HWMMap.getSectorName(sectorID).split(' ').join('<br>');
					td.appendChild(sectorName);

					const moveButton = document.createElement('img');
					moveButton.id = GM_info.script.namespace + "sector_move_" + sectorID;
					moveButton.src = 'https://dcdn.heroeswm.ru/i/speed_hunt.jpg';
					moveButton.style.padding = '0px 3px';
					moveButton.style.display = 'none';
					moveButton.style.cursor = 'pointer';
					moveButton.onclick = function(event){
						moveTo(sectorID);
					};
					td.appendChild(moveButton);

					const showButton = document.createElement('img');
					showButton.id = GM_info.script.namespace + "sector_info_" + sectorID;
					showButton.src = 'https://dcdn.heroeswm.ru/i/combat/map/notification_icon.png';
					showButton.style.width = '20px';
					showButton.style.height = '20px';
					showButton.style.padding = '0px 3px';
					showButton.style.display = 'none';
					showButton.style.cursor = 'pointer';
					showButton.onclick = function(event){
						location.assign('/map.php?cx=' + x + '&cy=' + y);
					};
					td.appendChild(showButton);
				}
				td.style.width = '65px';
				td.style.height = '40px';
				tr.appendChild(td);
			}
			table.appendChild(tr);
		}

		// remember new and new object
		this.nodeMapNew = table;
		this.nodeMapOld = getParentByTagName(document.getElementById('show_map'), 'table', 2);

		// inject table
		getParentByTagName(document.getElementById('show_map'), 'center', 1).prepend(table);
	},

	/**
	 * Apply map parameters
	 * @param map map parameters
	 * @param destination parameters
	 */
	apply(mapParams, destination){
		const colorLocation = 0x000099;
		const colorMercenary = 0x990000;
		const colorView = 0x009900;
		HWMMap.sectorList.forEach(function(s){
			const sector = document.querySelector('td[data-sector-id="' + s.id + '"]');
			let borderColor = 0x000000;

			// view
			if( s.id == mapParams.sectorView && s.id != mapParams.sector ){
				borderColor += colorView;
				sector.style.outlineStyle = 'solid';
			}

			// Mercenary guild
			if( s.id == mapParams.sectorMG || ( mapParams.sectorMG == -1 && HWMMap.sectorMercenary.includes(s.id) ) ){
				borderColor += colorMercenary;
				sector.style.outlineStyle = 'solid';
			}

			// location
			if( s.id == mapParams.sector ){
				borderColor += colorLocation;
			} else if( destination != 0 && s.id == destination ){
				borderColor += colorLocation;
				sector.style.outlineStyle = 'dashed';
			}

			// apply
			if( borderColor > 0 ){
				sector.style.outlineColor = '#' + borderColor.toString(16).padStart(6, '0');
				sector.style.outlineOffset = '-2px';
				sector.style.outlineWidth = '2px';
			} else {
				sector.style.outlineColor = '#000000';
				sector.style.outline = '1px solid';
				sector.style.outlineOffset = '-1px';
			}
		});
	},

	show(visible){
		if( this.nodeMapNew && this.nodeMapOld ){
			this.nodeMapNew.style.display = visible ? '' : 'none';
			this.nodeMapOld.style.display = visible ? 'none' : '';
		} else if( !this.nodeMapNew ) {
			log.error('Not found new map on the page');
		} else if( !this.nodeMapOld	) {
			log.error('Not found canvas map on the page');
		} else {
			log.error("WTF WE DOING HERE?");
		}
	},

	/**
	 * Link to old canvas map
	 */
	nodeMapOld: null,

	/**
	 * Link to new map
	 */
	nodeMapNew: null,
};

/**
 * Move to new sector
 * @param destination sector to move
 */
function moveTo(destination){
	const m = ls.get('map');
	// save to gm
	options.data.move.sectorID = destination == m.sector ? 0 : destination;
	options.data.move.save();
	// renew map if we use it
	if( document.getElementById('show_map')){
		MapObject.apply(ls.get('map'), destination );
		// emulate event for hide buttons
		let event = new Event("mouseleave");
		document.querySelector('td[data-sector-id="' + destination + '"]').dispatchEvent(event);
	}
	// clear old move call
	if( moveTimeoutID !== null ){
		clearTimeout(moveTimeoutID);
		moveTimeoutID = null;
	}
	// reach destination
	if( m.sector == destination ){
		log.info("Reach destination " + HWMMap.getSectorName(m.sector));
		// notify
		if( options.data.gm['map_notify'].value ){
			const notify = new Notify(GM_info.script.name);
			notify.send({
				body: 'Перемещение в ' + HWMMap.getSectorName(m.sector) + ' завершено',
				tag: 'map_move',
				timeout: 15000,
				onclick: function(event){
					parent.focus();
					window.focus();
					event.target.close();
				}
			});
		}
		return true;
	} else {
		const path = HWMMap.getPath(m.sector, destination);
		if( path.length == 0 ){
			log.error("Cannot find path from " + HWMMap.getSectorName(m.sector) + " to " + HWMMap.getSectorName(destination));
		} else {
			// wait a few seconds and go to a new sector
			log.info("Going to " + HWMMap.getSectorName(options.data.move.sectorID) + ". Next sector: " + HWMMap.getSectorName(path[0]));
			moveTimeoutID = setTimeout(function(){
				location.assign('/move_sector.php?id=' + path[0] + '&rand=' + Math.random());
			}, Math.random()*3000 + 1000);
			// notiyfy 
			if( options.data.gm['map_notify'].value ){
				const notify = new Notify(GM_info.script.name);
				notify.send({
					body: 'Перемещение в ' + HWMMap.getSectorName(destination) + '\nСледующий сектор: ' + HWMMap.getSectorName(path[0]),
					tag: 'map_move',
					timeout: 15000,
					onclick: function(event){
						parent.focus();
						window.focus();
						event.target.close();
					}
				});
			}
		}
	}
	return false;
}

/**
 * Replace map if needed and possible
 */
const testMapElement = document.getElementById('show_map');
if( testMapElement ) {
	const map = ls.get('map');

	// moving
	if( options.data.gm['map_hideonmove'].value && map.move ){
		const moveTimer = function(){
			const leftTime = (ls.get('mapTimestamp') + 2000 + 1000*map.moveTimeLeft - Date.now());

			// force reload page
			if( leftTime < 0 ){
				location.reload();
			} else {
				document.getElementById('map_move_timer').textContent = Math.floor(leftTime/1000);
				setTimeout(moveTimer, 200);
			}
		}
		const mapTable = getParentByTagName(document.getElementById('show_map'), 'table', 1);
		const infoTab = document.createElement('span');
		infoTab.style.fontSize = 24;
		infoTab.id = 'map_move_info';
		infoTab.innerHTML = '<b>Вы перемещаетесь в ' + HWMMap.getSectorName(map.sector) + '</b> \
							<br>До конца перемещения: <span id="map_move_timer"></span><br><br>';
		mapTable.style.display = 'none';
		mapTable.parentNode.prepend(infoTab);
		moveTimer();
	// not moving
	} else if( options.data.gm['map_replace'].value ){
		MapObject.init();
		MapObject.apply(ls.get('map'), options.data.move.sectorID );
		MapObject.show(true);
		// trying move to sector
		if( options.data.move.sectorID > 0 ){
			moveTo(options.data.move.sectorID);
		}
	}
}

/**
 * Reaction to change map object by other scripts
 */
document.addEventListener("localDataStorage", function (event) {
	if( options.data.gm['map_replace'].value && event.detail.prefix == LDSKey + '.' && event.detail.key == 'map' ){
		// redraw map
		MapObject.apply(event.detail.newval, 0);
		// emulate event for hide buttons
		HWMMap.sectorList.forEach(function(s){
			document.querySelector('td[data-sector-id="' + s.id + '"]').dispatchEvent(new Event('mouseleave'))
		});
	}
});

/**
 * Add move icon to mercenary_guild
 */
if( location.pathname == "/mercenary_guild.php" && options.data.gm['map_replace'].value ){
	const sectorLink = document.querySelector('a[href*="map.php?cx"]');
	if( sectorLink && mercenaryQuestStatus(document.body.innerHTML).status == 'old' ){
		const params = (new URL(sectorLink.href)).searchParams;
		const moveButton = document.createElement('IMG');
		moveButton.id = GM_info.script.namespace + "sector_move_" + HWMMap.getSectorIDFromXY(params.get('cx'), params.get('cy'));
		moveButton.src = 'https://dcdn.heroeswm.ru/i/speed_hunt.jpg';
		moveButton.style.height = '15px';
		moveButton.style.marginBottom = "-5px";
		moveButton.style.cursor = 'pointer';
		moveButton.onclick = function(event){
			moveTo(HWMMap.getSectorIDFromXY(params.get('cx'), params.get('cy')));
		}
		sectorLink.parentNode.insertBefore(moveButton, sectorLink.nextSibling);
		// hide original horse button
		const horse = document.querySelector('img[src*="horse_gif.gif"]');
		if( horse ){
			horse.remove();
		}
	}
}

/**
 * Add move icon to hunts
 */
if( location.pathname == "/group_wars.php" && options.data.gm['map_replace'].value ){
	document.querySelectorAll('a[href*="map.php?cx"]').forEach(function(hunt){
		const params = (new URL(hunt.href)).searchParams;
		const moveButton = document.createElement('IMG');
		moveButton.id = GM_info.script.namespace + "sector_move_" + HWMMap.getSectorIDFromXY(params.get('cx'), params.get('cy'));
		moveButton.src = 'https://dcdn.heroeswm.ru/i/speed_hunt.jpg';
		moveButton.style.height = '15px';
		moveButton.style.marginBottom = "-4px";
        moveButton.style.marginLeft = "4px";
		moveButton.style.cursor = 'pointer';
		moveButton.onclick = function(event){
            event.preventDefault();
			moveTo(HWMMap.getSectorIDFromXY(params.get('cx'), params.get('cy')));
		}
		hunt.append(moveButton);
		hunt.style.whiteSpace = 'nowrap';
	});
}

/**
 * Fill settings tab
 */
const tab = SettingsTab.add('Map', 'Карта');
Object.keys(options.data.gm).forEach(function(key){
	if( typeof options.data.gm[key] === 'function' ){
		return;
	}
	const input = document.createElement('input');
	input.id = key;
	input.type = 'checkbox';
	input.checked = options.data.gm[key].value;
	input.addEventListener('change', function(event){
		options.data.gm[event.target.id].value = event.target.checked;
		options.data.gm.save();
	});

	const label = document.createElement('label');
	label.htmlFor = key;
	label.textContent = options.data.gm[key].name;

	tab.appendChild(input);
	tab.appendChild(label);
	tab.appendChild(document.createElement('br'));
});
